﻿using System;
using System.Collections.Generic;
using System.Text;
using Xeno.Core;

using OpenTK.Graphics.OpenGL;
using OpenTK;

namespace Xeno.Core
{
    public delegate void XuiEvent(XuiWidget widget,int data,object obj,int x,int y);
    public enum CyberBlend
    {
        Solid,Alpha,Additive,Mod,ModX2,ModX4,Subtract,Lighten,Darken,Burn,SoftLight,HardLight,OR,XOR,NOT
    }
    public class Cyber2D
    {
        public static Vector4 Color = new Vector4(1.0f, 1.0f, 1.0f, 0.85f);
        public static Vector4 TextColor = new Vector4(0.0f, 0.0f, 0.0f, 0.85f);
        public static Vector3 Rotation = new Vector3(0, 0, 0);
        public static Vector3 UVScale = new Vector3(1.0f, 1.0f, 1.0f);
        public static Dictionary<string, XenoText.XenoTextCache> TextCache = new Dictionary<string, XenoText.XenoTextCache>();
        public static CyberBlend BlendMode = CyberBlend.Alpha;

        public static Vector4 Col(float r, float g, float b, float a)
        {
            return new Vector4(r, g, b, a);
        }
        public static Vector4 Col(float r, float g, float b)
        {
            return Col(r, g, b, Color.W);
        }
        public static Vector4 Col1(float r, float g, float b)
        {
            return Col(r, g, b, 1.0f);
        }
        public static Vector4 SetCol(float r, float g, float b, float a)
        {
            Color = Col(r, g, b, a);
            return Color;
        }
        public static Vector4 SetCol(float r, float g, float b)
        {
            Color = Col(r, g, b);
            return Color;
        }
        public static Vector4 SetCol1(float r, float g, float b)
        {
            Color = Col1(r, g, b);
            return Color;
        }
        public static void Begin()
        {
            XuiWidget.Begin2D();
            Rotation = Vector3.Zero;
        }
        public static void End()
        {
            XuiWidget.End2D();
        }
        public static void Frame(Vector4 pos)
        {

            Frame(pos, null);

        }
        public static void Text(Vector2 pos, string txt)
        {

            XenoText.XenoTextCache tx = null;

            if (TextCache.ContainsKey(txt))
            {
                tx = TextCache[txt];
            }
            else
            {

                tx = XenoText.CreateText(txt);
                TextCache.Add(txt, tx);
            }

            XenoText.DrawText(tx, (int)pos.X, (int)pos.Y, System.Drawing.Color.FromArgb((int)(TextColor.W * 255.0f), (int)(TextColor.X * 255.0f), (int)(TextColor.Y * 255.0f), (int)(TextColor.Z * 255.0f)));


        }



        private static  void Bind()
        {
            GL.PushAttrib(AttribMask.AllAttribBits);
            switch (BlendMode)
            {

                case CyberBlend.Alpha:

                    GL.Enable(EnableCap.Blend);
                    GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
                    GL.Disable(EnableCap.AlphaTest);

                    break;

            }

        }
        private static void Unbind()
        {
            GL.PopAttrib();
        }

        public static Vector2[] ProjectFrame(Vector4 pos, Vector3 rot,float z)
        {

            float mw, mh;

            mw = pos.Z / 2.0f;
            mh = pos.W / 2.0f;

            Vector2[] r = new Vector2[4];

            //var m = Matrix4.CreateRotationY(rot.Y);
            //m *= Matrix4.CreateRotationX(rot.X);
            //m *= Matrix4.CreateRotationZ(rot.Z);
            var q = Quaternion.FromAxisAngle(new Vector3(0, 1, 0), MathHelper.DegreesToRadians(rot.Y));
            q *= Quaternion.FromAxisAngle(new Vector3(1, 0, 0), MathHelper.DegreesToRadians(rot.X));


            float px, py;

            px = 0;
            py = 0;

            r[0] = GetPoint(ref q, px, py,mw,mh,pos.X,pos.Y);
            r[1] = GetPoint(ref q, px + pos.Z, py, mw, mh,pos.X,pos.Y);
            r[2] = GetPoint(ref q, px + pos.Z, py + pos.W, mw, mh,pos.X,pos.Y);
            r[3] = GetPoint(ref q, px, py + pos.W, mw, mh,pos.X,pos.Y);

            return r;

        }

        private static Vector2 GetPoint(ref Quaternion q, float px, float py,float mw,float mh,float sx,float sy)
        {
            px -= mw;
            py -= mh;

            Matrix4 tmp = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(1.0f), (float)XenoCore.DisplayWidth/(float)XenoCore.DisplayHeight, 0.1f, 100.0f);
          //  tmp = Matrix4.CreatePerspectiveOffCenter(0,Global.DisplayWidth,Global.DisplayHeight,0.0f,0.1f,1000.0f);
            var np3 = Vector3.Transform(new Vector3(px, py,20.0f), q);


            np3 = Vector3.TransformPerspective(np3, tmp);
            var np = new Vector2(np3.X,np3.Y);
            
            np.X +=sx+ mw;
            np.Y +=sy+mh;

         

            return np;
        }

        public static void Frame(Vector4 pos, XenoTexture2D tex)
        {

            //Vector2[] pp = ProjectFrame(pos, Rotation, 0.0f);




            Bind();

            GL.Color4(Color);

            tex.Bind(0);

            GL.Begin(BeginMode.Quads);

            GL.TexCoord2(0.0f, 0.0f);
            GL.Vertex2(pos.X, pos.Y);

            GL.TexCoord2(1.0f * UVScale.X, 0.0f);
            GL.Vertex2(pos.X+pos.Z,pos.Y);
            

            GL.TexCoord2(1.0f * UVScale.X, 1.0f * UVScale.Y);
            GL.Vertex2(pos.X+pos.Z,pos.Y+pos.W);


          

            GL.TexCoord2(0.0f, 1.0f * UVScale.Y);
            GL.Vertex2(pos.X,pos.Y+pos.W);

         

            GL.End();

            tex.Unbind(0);

            Unbind();

        }
    }

    public class XuiWidget : XenoModule
    {
        
        public Vector3 Size { get; set; }
        public XuiEvent Action { get; set; }
        public XenoNode UserNode { get; set; }
        public bool CullNodes { get; set; }
        public XuiWidget(Vector2 size)
        {

            Size = new Vector3(size.X, size.Y,0);
            Action = null;
            CullNodes = true;

        }
        public bool InBounds(Vector3 pos)
        {
            Vector3 wp = Attached.WorldPosition;
            return(pos.X>=wp.X && pos.Y>=wp.Y && pos.X<=wp.X+Size.X && pos.Y<=wp.Y+Size.Y);

        }
        public static void Begin2D()
        {
            GL.PushAttrib(AttribMask.AllAttribBits);

            GL.MatrixMode(MatrixMode.Projection);
            GL.LoadIdentity();

            Matrix4 projectionMatrix = Matrix4.CreateOrthographicOffCenter(0, XenoCore.DisplayWidth, XenoCore.DisplayHeight, 0, 0, 2);

            GL.LoadMatrix(ref projectionMatrix);
            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadIdentity();


            GL.Disable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            GL.Disable(EnableCap.AlphaTest);
        

            GL.DepthMask(false);
        }
        public static void End2D()
        {
            GL.PopAttrib();
        }

    }

}
